home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Ja, Du hast Recht. Einmal allozierter Speicher wird nicht wieder
- freigegeben. Das hat mich auch schon immer gestoert, ich hatte aber
- nie die Zeit daran mal was zu aendern.
- QED holt sich vom System immer Bloecke einer bestimmten Groesse und
- verwaltet sie dann selbst. Eine richtige garbage collection findet
- nicht statt. Werden aber zwei Zeilen, die im Speicher hintereinander
- gelegen haben wieder frei gegeben, werden sie wieder zu einem grossen
- Block verschmolzen. Das erfolgt sehr effizient (und damit ist der Code
- ziemlich grausam).
- Alle freien Bloecke einer Groesse werden in einer verketteten Liste
- gehalten. Die Anfaenge dieser Listen stehen in einem Array. Um bei der
- freigabe einer Zeile aber nun schnell festzustennen, ob dahinter noch
- ein anderer freier Block ist (und nicht erst alle Listen durchlaufen
- zu muessen), mit dem der erste dann verschmolzen
- werden kann, gibt es dieses MAGIC-Word. Ich sehe also direkt im
- Speicher hinter dem ersten Block nach, ob dort das Magic-Word
- steht. Wenn ja, dann liegt dort ein freier Block. Damit ich weiss um
- einen Block welcher Groesse es sich handelt, steht dort auch noch die
- Groessse und fuer eine einfache Umhaengung in den Listen auch gleich die
- Zeiger auf Vorgaenger und Nachfolger in der Liste.
- Lange Rede, kurzen Sinn: mit diesem Verfahren ist es moeglich in
- *konstanter* Zeit eine Free-Operation mit Verschmelzung zu
- realisieren.
- Aber daran brauchst Du wohl garnichts aendern, wenn Du das Programm so
- verbessern willst, dass es den Speicher ans System wieder
- zurueckgibt. Du musst nur ueberpruefen, ob ein Block komplett frei
- ist. Wenn das der Fall ist, musst Du alle kleinen Bloecke aus den
- free_list-Listen herausnehemen und kannst dann den Block ans System
- zureuckgeben.
-
- */
-
- #include "global.h"
- #include "qed.h"
- #include "text.h"
- #include "windows.h"
- #include "scroll.h"
-
- #undef MAGIC
- #define MAGIC 0xFED1
- #define MAX_ANZ 67
- #define BLOCK_SIZE (MAX_ANZ*4)
- #define BLOCKANZ 200 /* Für einen malloc */
- #define MEMSIZE ((LONG)BLOCK_SIZE*BLOCKANZ) /* für einen malloc */
-
- #define MEM_SIZE(x) (((x)+2+3)&(~3)) /* 2 Bytes drauf für den Kopf */
- #define MEM_ADD(x,d) (BLOCK*)((char*)(x)+(d))
- #define MEM_SUB(x,d) (BLOCK*)((char*)(x)-(d))
-
- typedef union tblock{
- struct{
- UWORD magic; /* 2 Bytes */
- UWORD size; /* 2 Bytes */
- union tblock *next; /* 4 Bytes */
- union tblock *prev; /* 4 Bytes => 12 Bytes */
- }FREI;
- struct{
- UWORD size; /* 2 Bytes */
- }USED;
- } BLOCK;
-
- LOCAL BOOLEAN mem_need_BS, /* BS hat keinen Speicher mehr */
- mem_need_TQ; /* TQ hat keinen Speicher mehr */
- LOCAL VOID* block_list;
- LOCAL BLOCK* free_list[MAX_ANZ+1+1]; /* ein Dummy am Ende */
-
-
-
- LOCAL VOID new_block(VOID)
- {
- BLOCK *adr, *adr2, *pre;
- LONG *ptr;
- LONG anz, i;
-
- anz = (LONG)Malloc(-1L);
- if (anz>=4+MEMSIZE+4)
- {
- ptr = (LONG*)Malloc(4+MEMSIZE+4);
- anz -= 4+MEMSIZE+4;
- }
- else
- ptr = NULL;
- if (anz < MEMSIZE+20000L)
- mem_need_BS = TRUE;
- if (ptr == NULL)
- {
- if (anz>=4+BLOCK_SIZE+4)
- {
- i = anz = (anz-8)/(BLOCK_SIZE);
- anz = 4+(anz*BLOCK_SIZE)+4;
- ptr = (LONG*)Malloc(anz);
- }
- else
- {
- note(1, FATALMEM);
- Pterm(1);
- }
- mem_need_TQ = TRUE;
- }
- else
- {
- i = BLOCKANZ;
- mem_need_TQ = FALSE;
- }
-
- *(VOID**)ptr = block_list; /* In Liste einhängen */
- block_list = ptr;
- adr = MEM_ADD(ptr,4);
-
- free_list[MAX_ANZ] = adr;
- pre = NULL;
- while ((--i)>0)
- {
- adr2 = MEM_ADD(adr,BLOCK_SIZE);
- *(LONG*)&adr->FREI.magic = (LONG)(MAGIC<<16)+BLOCK_SIZE;
- /* adr->FREI.magic = MAGIC; */
- /* adr->FREI.size = BLOCK_SIZE; */
- adr->FREI.next = adr2;
- adr->FREI.prev = pre;
- pre = adr;
- adr = adr2;
- }
- adr2 = MEM_ADD(adr,BLOCK_SIZE);
- *(LONG*)&adr->FREI.magic = (LONG)(MAGIC<<16)+BLOCK_SIZE;
- /* adr->FREI.magic = MAGIC; */
- /* adr->FREI.size = BLOCK_SIZE; */
- adr->FREI.next = NULL;
- adr->FREI.prev = pre;
-
- *(LONG*)adr2 = 0L; /* damit bei FREE da kein MAGIC steht */
- }
-
- LOCAL VOID *MALLOC(UWORD size)
- {
- BLOCK *adr, **feld;
-
- size = MEM_SIZE(size);
- if (size>BLOCK_SIZE)
- {
- inote(1, FATALERR, 5);
- size = BLOCK_SIZE;
- }
- feld = (BLOCK**)((char*)free_list+size);
- if (*feld==NULL) /* kein passender */
- {
- if (size+16<=BLOCK_SIZE) /* grö₧eren Block suchen und teilen */
- {
- BLOCK *adr2;
- WORD i;
-
- i = size+16; feld += 4; /* 16 Bytes kleinster Block zum Abspalten */
- while (TRUE) /* grö₧eren Block suchen */
- {
- if (*feld++!=NULL) break; i+=4;
- if (*feld++!=NULL) break; i+=4;
- if (*feld++!=NULL) break; i+=4;
- if (*feld++!=NULL) break; i+=4;
- if (*feld++!=NULL) break; i+=4;
- if (*feld++!=NULL) break; i+=4;
- if (*feld++!=NULL) break; i+=4;
- if (*feld++!=NULL) break; i+=4;
- }
- feld--;
- if (i==(BLOCK_SIZE+4)) /* kein Block vorhanden */
- {
- new_block();
- feld--; i-=4;
- }
- adr = *feld; /* Zeiger auf Block */
- *feld = adr->FREI.next; /* Aushängen */
- if (*feld!=NULL) (*feld)->FREI.prev = NULL;
- adr->USED.size = size;
-
- /* Rest in die free_list einhängen */
- adr2 = MEM_ADD(adr,size); /* Zeiger auf Restblock */
- (char*)feld -= size;
- i -= size; /* Restgrö₧e */
- adr2->FREI.magic = MAGIC; /* Einhängen */
- adr2->FREI.size = i;
- adr2->FREI.next = *feld;
- adr2->FREI.prev = NULL;
- if (*feld!=NULL) (*feld)->FREI.prev = adr2;
- *feld = adr2;
- }
- else /* grö₧ten Block nehmen */
- {
- feld = (BLOCK**)(&free_list[MAX_ANZ]);
- if (*feld==NULL) /* kein Block vorhanden */
- new_block();
- adr = *feld; /* Zeiger auf Block */
- *feld = adr->FREI.next; /* Aushängen */
- if (*feld!=NULL) (*feld)->FREI.prev = NULL;
- adr->USED.size = BLOCK_SIZE;
- }
- }
- else /* passend vorhanden */
- {
- adr = *feld; /* Zeiger auf Block */
- *feld = adr->FREI.next; /* Aushängen */
- if (*feld!=NULL) (*feld)->FREI.prev = NULL;
- adr->USED.size = size;
- }
- if (free_list[MAX_ANZ]==NULL)
- mem_need_TQ = TRUE;
- return(MEM_ADD(adr,2));
- }
-
- LOCAL VOID FREE(VOID *adr)
- {
- WORD size1, size2;
- BLOCK *adr1, *adr2, **feld;
-
- adr1 = MEM_SUB(adr,2); /* adr1 auf ersten Block */
- size1 = adr1->USED.size;
- /*#ifdef CONCAT*/
- adr2 = MEM_ADD(adr1,size1); /* adr2 auf Nachfolger */
- size2 = adr2->FREI.size;
- if (adr2->FREI.magic==MAGIC && (size1+size2<=BLOCK_SIZE))
- /* freier Block dahinter => Zusammenfügen */
- {
- BLOCK *pre;
-
- pre = adr2->FREI.prev; /* Aushängen */
- if (pre==NULL) /* erster in der Liste */
- *(BLOCK**)((char*)free_list+size2) = adr2->FREI.next;
- else
- pre->FREI.next = adr2->FREI.next;
- if (adr2->FREI.next!=NULL) /* es gibt Nachfolger */
- adr2->FREI.next->FREI.prev = pre;
- size1 += size2;
- }
- /*#endif*/
- feld = (BLOCK**)((char*)free_list+size1); /* Einhängen */
- adr1->FREI.magic = MAGIC;
- adr1->FREI.size = size1;
- adr1->FREI.next = *feld;
- adr1->FREI.prev = NULL;
- if (*feld!=NULL) (*feld)->FREI.prev = adr1;
- *feld = adr1;
-
- if (size1==BLOCK_SIZE)
- mem_need_TQ = FALSE;
- }
-
- /* =========================================================== */
-
- VOID INSERT(LINEP *a, WORD pos, WORD delta, const char *str)
- {
- COPYB(REALLOC(a,pos,delta),str,delta);
- }
-
- /* =========================================================== */
-
- char *REALLOC(LINEP *a, WORD pos, WORD delta)
- {
- LINEP col;
- WORD new_len;
- BLOCK *adr;
-
- col = *a;
- if (delta==0) return(TEXT(col)+pos);
-
- new_len = col->len+delta;
- if (new_len<0 || new_len>MAX_LINE_LEN)
- note(1, FATALMEM);
- adr = MEM_SUB(col,2);
- if (MEM_SIZE((UWORD)sizeof(ZEILE)+new_len+1) != adr->USED.size)
- {
- LINEP new;
-
- new = MALLOC( (short) sizeof(ZEILE) + new_len + 1);
- COPYW(new, col, (short) sizeof(ZEILE)+pos);
- if (delta<0)
- {
- new->len = new_len;
- COPYB(TEXT(new)+pos,TEXT(col)+pos-delta,new_len-pos+1);
- }
- else
- {
- COPYB(TEXT(new)+pos+delta,TEXT(col)+pos,col->len-pos+1);
- new->len = new_len;
- }
- FREE(col);
- new->vorg->nachf = new;
- new->nachf->vorg = new;
- *a = new;
- return(TEXT(new)+pos);
- }
- else /* Der Platzt in der Zeile reicht */
- {
- if (delta<0)
- {
- col->len = new_len;
- COPYB(TEXT(col)+pos,TEXT(col)+pos-delta,new_len-pos+1);
- }
- else
- {
- MOVE(TEXT(col)+pos+delta,TEXT(col)+pos,col->len-pos+1);
- col->len = new_len;
- }
- return(TEXT(col)+pos);
- }
- }
-
- LINEP new_col_w(const char *str, WORD l)
- {
- LINEP a;
-
- a = (LINEP)MALLOC( (short) sizeof(ZEILE)+l+1);
- a->info = 0;
- a->len = l;
- COPYW(TEXT(a),str,l);
- TEXT(a)[l] = EOS;
- return(a);
- }
-
- LINEP new_col_b(const char *str, WORD l)
- {
- LINEP a;
-
- a = (LINEP)MALLOC( (short)sizeof(ZEILE)+l+1);
- a->info = 0;
- a->len = l;
- if ((WORD)str&1)
- {
- *(char*)COPYB(TEXT(a),str,l) = EOS;
- }
- else
- {
- COPYW(TEXT(a),str,l);
- TEXT(a)[l] = EOS;
- }
- return(a);
- }
-
- VOID free_col(LINEP col)
- {
- FREE(col);
- }
-
- /* Zeile nach WO einfügen */
- LINEP col_insert(LINEP wo, LINEP was)
- {
- LINEP help;
-
- help = wo->nachf;
- help->vorg = was;
- was->nachf = help;
- was->vorg = wo;
- wo->nachf = was;
- return was;
- }
-
- /* Zeile am Ende anhängen */
- VOID col_append(RINGP t, LINEP was)
- {
- LINEP help;
-
- help = LAST(t);
- was->vorg = help;
- was->nachf = help->nachf;
- help->nachf = was;
- t->tail.vorg = was;
- t->lines++;
- }
-
- VOID col_delete(LINEP wo)
- {
- wo->vorg->nachf = wo->nachf;
- wo->nachf->vorg = wo->vorg;
- FREE(wo);
- }
-
- VOID col_concate(LINEP *wo)
- {
- LINEP help, col;
- BOOLEAN absatz;
-
- col = *wo;
- help = col->nachf;
- if (col->len)
- {
- absatz = help->info&ABSATZ;
- INSERT(&col, col->len, help->len, TEXT(help));
- help->nachf->vorg = col;
- col->nachf = help->nachf;
- FREE(help);
- if (absatz)
- col->info |= ABSATZ;
- else
- col->info &= ~ABSATZ;
- *wo = col;
- }
- else
- {
- col->vorg->nachf = help;
- help->vorg = col->vorg;
- FREE(col);
- *wo = help;
- }
- }
-
- VOID col_split(LINEP *col,WORD pos)
- {
- LINEP new,help;
- WORD anz;
- BOOLEAN absatz;
-
- help = *col;
- absatz = help->info&ABSATZ;
- help->info &= ~ABSATZ;
- if (pos==0)
- {
- new = new_col_w ("",0);
- col_insert(help->vorg,new);
- *col = new;
- }
- else if (pos<help->len)
- {
- anz = help->len-pos;
- new = new_col_b (TEXT(help)+pos, anz);
- col_insert (help, new);
- REALLOC(&help,pos,-anz);
- *col = help;
- }
- else
- {
- new = new_col_w ("",0);
- col_insert(help,new);
- }
- if (absatz) (*col)->nachf->info |= ABSATZ;
- else (*col)->nachf->info &= ~ABSATZ;
- }
-
- LINEP get_line(RINGP r, LONG y)
- {
- LINEP lauf;
-
- if (y<0 || y>=r->lines) return NULL;
- if (y<(r->lines>>1))
- {
- lauf = FIRST(r);
- while ((--y)>=0) NEXT(lauf);
- }
- else
- {
- lauf = LAST(r);
- y = r->lines-y;
- while ((--y)>0) VORG(lauf);
- }
- return lauf;
- }
-
- /*=========================================================================*/
-
- VOID init_textring(RINGP r)
- {
- LINEP a;
-
- r->head.info = HEAD;
- r->tail.info = TAIL;
- a = new_col_w("",0);
- a->nachf = &r->tail;
- a->vorg = &r->head;
- LAST(r) = a;
- r->tail.nachf = NULL;
- FIRST(r) = a;
- r->head.vorg = NULL;
- r->lines = 1;
- r->longest_len = 0;
- }
-
- LONG textring_bytes(RINGP r, LineEnding ending)
- {
- LINEP lauf, ende;
- LONG bytes;
-
- lauf = FIRST(r);
- ende = LAST(r);
- bytes = lauf->len;
- while(lauf!=ende)
- {
- NEXT(lauf);
- bytes += lauf->len;
- }
- /* plus Zeilenenden: 1 Zeichen für alle */
- bytes += r->lines-1;
- if (ending == tos)
- /* für TOS noch ein Zeichen */
- bytes += r->lines-1;
- return bytes;
- }
-
-
- WORD get_longest_len(RINGP r)
- {
- /*
- WORD max;
- LINEP lauf;
-
- max = 0;
- lauf = FIRST(r);
- if (lauf != NULL)
- {
- while (!IS_LAST(lauf))
- {
- if (lauf->len > max)
- max = lauf->len;
- NEXT(lauf);
- }
- r->longest_len = max;
- }
- return max;
- */
- return 0;
- }
-
- VOID free_textring(RINGP r)
- {
- LINEP lauf, frei, ende;
-
- frei = LAST(r); /* letzte Zeile */
- lauf = frei->vorg; /* vorletzte Zeile */
- ende = FIRST(r); /* erste Zeile */
- while (frei!=ende)
- {
- FREE(frei);
- frei = lauf;
- VORG(lauf);
- }
- LAST(r) = frei;
- frei->nachf = &r->tail;
- REALLOC(&frei,0,-(frei->len));
- frei->info = 0;
- r->lines = 1;
- }
-
- VOID kill_textring(RINGP r)
- {
- free_textring(r);
- FREE(FIRST(r));
- FIRST(r) = NULL;
- LAST(r) = NULL;
- r->lines = 0;
- }
-
- BOOLEAN doppeln(RINGP old, RINGP new)
- {
- LINEP lauf, neu, a;
- LONG lines, anz;
- BOOLEAN erg;
-
- erg = TRUE;
- free_textring(new);
- a = FIRST(new);
- lauf = FIRST(old);
- anz = old->lines;
-
- INSERT(&a, 0, lauf->len, TEXT(lauf));
- a->info = lauf->info;
- NEXT(lauf);
- NEXT(a);
- lines = 1L;
- while (lines<anz)
- {
- neu = new_col_w(TEXT(lauf),lauf->len);
- neu->info = lauf->info; /* ABSATZ mit kopieren */
- col_insert(a->vorg,neu);
- NEXT(lauf);
- lines++;
- if (!ist_mem_frei())
- {
- erg = FALSE;
- break;
- }
- }
- new->lines = lines;
- return erg;
- }
-
- BOOLEAN ist_leer(RINGP r)
- {
- return(r->lines==1 && FIRST(r)->len==0);
- }
-
- /*=========================================================================*/
-
- VOID kill_memory(VOID)
- {
- WORD i;
- BLOCK **ptr;
- VOID *help;
-
- for (i=MAX_ANZ+1,ptr=free_list; (--i)>=0; )
- {
- *ptr++ = NULL;
- }
- while (block_list!=NULL)
- {
- help = *(VOID**)block_list; /* nächster Block */
- Mfree(block_list);
- block_list = help;
- }
- mem_need_TQ = mem_need_BS = FALSE;
- }
-
- BOOLEAN is_mem_free(VOID)
- {
- return (!(mem_need_BS && mem_need_TQ));
- }
-
- BOOLEAN ist_mem_frei(VOID)
- {
- if (mem_need_BS && mem_need_TQ)
- {
- note(1,NOMEMORY);
- return (FALSE);
- }
- else
- return (TRUE);
- }
-
- VOID init_memory(VOID)
- {
- WORD i;
- BLOCK **ptr;
-
- mem_need_TQ = mem_need_BS = FALSE;
- for (i=MAX_ANZ+1,ptr=free_list; (--i)>=0; )
- *ptr++ = NULL;
- *ptr = (VOID*)-1L; /* für schleifenende */
- block_list = NULL;
- }
-